﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using HtmlAgilityPack;
using MiniCrawler;
using MiniCrawler.Business.Collectors;
using MiniCrawler.Business.Collectors.LinkCollectors;
using MiniCrawler.Logging;
using MiniCrawler.Models;

namespace MiniCrawler.Business
{
    class BBC : ILinkCollector
    {
        private DateTime start;

        private string url = "http://www.bbc.co.uk/worldservice/learningenglish/";
        private string hostName = "http://www.bbc.co.uk/";
        private string sampleCategoryLink = "http://www.bbc.co.uk/worldservice/learningenglish/general/englishatwork/";

        private string sampleNewsLink =
            "http://www.bbc.co.uk/worldservice/learningenglish/general/englishatwork/2012/10/121024_english_at_work_37_story.shtml";

        public static List<string> GetCategoryLinks(string html)
        {
            List<string> result = new List<string>();
            var doc = new HtmlDocument();
            doc.LoadHtml(html);

            // Select all category nodes with class = 'jazin-section'
            var catNodes = doc.DocumentNode.SelectNodes("//div[@class='jazin-section']");
            var subCatNodes = doc.DocumentNode.SelectNodes("//div[@class='jazin-categories']");

            // Get all urls of nodes
            foreach (HtmlNode image in catNodes)
            {
                var links = image.SelectNodes("a");
                foreach (var link in links)
                {
                    HtmlAttribute att = link.Attributes["href"];
                    var m = att.Value;
                    result.Add(m);
                }
            }

            foreach (HtmlNode subCatNode in subCatNodes)
            {
                var links = subCatNode.SelectNodes("a");
                foreach (var link in links)
                {
                    HtmlAttribute att = link.Attributes["href"];
                    var m = att.Value;
                    result.Add(m);
                }
            }

            return result;


        }

        public List<CategoryLink> GetAllCategoryLinks(List<CategoryLink> oldLinks, List<string> allLinks)
        {
            var t = oldLinks;

            if (allLinks.Count > 0)
            {
                foreach (var link in allLinks)
                {

                    if (IsCategoryLink(link) && !Utils.IsContainCategoryLink(t, link))
                    {
                        Log.WriteLog("[ADD CATEGORY]" + link);
                        t.Add(new CategoryLink(link, false));
                    }
                }
            }
            return t;
        }

        public List<NewsLink> GetAllNewsLink(List<NewsLink> oldLinks, List<string> allLinks)
        {
            var t = oldLinks;
            if (allLinks.Count > 0)
            {
                foreach (var link in allLinks)
                {

                    if (IsDataLink(link) && !Utils.IsContainNewsLink(t, link))
                    {
                        Log.WriteLog("[ADD NEWS]" + link);
                        t.Add(new NewsLink(link, false));
                    }
                }
            }
            return t;
        }

        public void Run()
        {
            try
            {


                //return;
                start = DateTime.Now;

                string html = Common.GetWebPage(url);

                var s = 0;
                var t0 = Utils.GetAllLinks(html);

                // Get from homepage

                var catLinks = GetAllCategoryLinks(new List<CategoryLink>(), t0);

                Log.WriteElapseTime(start);

                var newsLink = GetAllNewsLink(new List<NewsLink>(), t0);

                Log.WriteElapseTime(start);

                // Scan cat link
                while (!Utils.IsFullyCheckedCategoryLink(catLinks))
                {

                    int currentLength = catLinks.Count;
                    for (int i = 0; i < currentLength; i++)
                    {
                        var catLink = catLinks[i];
                        Log.WriteLog("[GET FROM : " + catLink.Link + "]");

                        Log.WriteLog("[CATEGORY : " + catLinks.Count + "][CHECKED : " + Utils.GetNumberOfChecked(catLinks) + "]");
                        Log.WriteLog("[NEWS     : " + newsLink.Count + "][CHECKED : " + Utils.GetNumberOfChecked(newsLink) + "]");

                        catLink.Checked = true;

                        string cathtml = Common.GetWebPage(FillAbsoluteUrl(hostName, catLink.Link));

                        catLinks = GetAllCategoryLinks(catLinks, Utils.GetAllLinks(cathtml));
                        newsLink = GetAllNewsLink(newsLink, Utils.GetAllLinks(cathtml));

                        Log.WriteElapseTime(start);
                    }

                }


                //Log.WriteLog("[-----------------DOWN LOAD NEWS CONTENT-------------------------------------------]");
                List<News> lstNews = new List<News>();
                int z = 0;

                foreach (var link in newsLink)
                {
                    Log.WriteLog("[DOWNLOAD : " + z + "/" + newsLink.Count + "]");
                    News n = GetNewsContent(link.Link);

                    if (n != null)
                    {
                        Log.WriteLog("[DOWNLOADED]" + link.Link);
                        Log.WriteElapseTime(start);
                        //Utils.TransferNewsToToaSoan(n);
                        Log.WriteElapseTime(start);
                        z++;
                    }

                }




                var flag = 0;




            }
            catch (Exception ex)
            {

                LogService.Service.Error(ex);
            }

        }

        public string FillAbsoluteUrl(string hostName, string url)
        {
            if (url.StartsWith("/")) return hostName + url;
            else return url;
        }

        public bool IsCategoryLink(string link)
        {

            int t = link.LastIndexOf('/');
            if (link.EndsWith(".shtml")) return false;
            if (!link.Contains("worldservice/learningenglish/")) return false;
            if (!link.EndsWith("/")) return false;

            return true;
        }

        public bool IsDataLink(string link)
        {

            int t = link.LastIndexOf('/');

            if (!link.EndsWith(".shtml")) return false;
            if (!link.Contains("worldservice/learningenglish/")) return false;

            string s = link.Substring(link.LastIndexOf('/') + 1, 1);
            if (IsNumeric(s)) return true;
            else return false;
        }

        private static bool IsNumeric(string number)
        {
            int t = -1;
            var x = int.TryParse(number, out t);
            return x;
        }

        public static string CreatePath(string name)
        {
            string strNewName = name;

            #region Replace unicode chars
            Regex regex = new Regex("\\p{IsCombiningDiacriticalMarks}+");
            string temp = name.Normalize(NormalizationForm.FormD);
            strNewName = regex.Replace(temp, String.Empty).Replace('\u0111', 'd').Replace('\u0110', 'D');
            #endregion

            #region Replace special chars
            string strSpecialString = "~\"“”#%&*:;<?/\\{|}.+_@$^()[]`,!";

            foreach (char c in strSpecialString.ToCharArray())
            {
                strNewName = strNewName.Replace(c, ' ');
            }
            #endregion

            #region Replace space

            // Create the Regex.
            var r = new Regex(@"\s+");
            // Strip multiple spaces.
            strNewName = r.Replace(strNewName, @" ");
            strNewName = strNewName.Replace(">", "/");
            strNewName = strNewName.Trim();

            #endregion

            return strNewName;
        }

        public News GetNewsContent(string link)
        {
            try
            {
                if (link.StartsWith("/")) link = hostName + link;

                string html = Common.GetWebPage(link);
                News n = new News();
                if (!string.IsNullOrEmpty(html))
                {

                    string mhtml = html;
                    var doc = new HtmlDocument();
                    doc.LoadHtml(mhtml);

                    // Select all category nodes with class = 'jazin-section'
                    // Select id


                    var cumberNode = doc.DocumentNode.SelectSingleNode("//div[@id='crumbtrail']");
                    var cumber = Utils.GetInnerText(cumberNode);
                    cumber = CreatePath(cumber);
                    
                    var titleNode = doc.DocumentNode.SelectSingleNode("//div[@id='page-title']/h1[1]");
                    n.Title = Utils.GetInnerText(titleNode);
                    n.Url = link;

                    var audioNode = doc.DocumentNode.SelectSingleNode("//div[@id='relateddownloads0'][1]");

                    List<string> links = Utils.GetAllLinks(audioNode.InnerHtml);

                    if(links != null && links.Count > 0)
                    {
                        if(links[0] != null)
                        {
                            n.Summary = links[0];
                        }
                        if(links.Count > 1)
                        {
                            if (links[1] != null)
                            {
                                n.Content = links[1];
                            } 
                        }
                        
                    }

                    DownloadFiles(n.Content, cumber);
                    DownloadFiles(n.Summary, cumber);
                    

                }
                return n;


            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
                return null;
            }

        }

        public void RemoveNode(HtmlNode root, HtmlNode node)
        {
            try
            {

                if (node.ParentNode == root)
                {
                    root.RemoveChild(node);
                }
                else
                {
                    node.Remove();
                }
            }
            catch (Exception ex)
            {
                var flag = 0;
            }
        }


        private void DownloadFiles(string url, string folder)
        {

            try
            {
                string s = "D:\\BBC\\";
                Directory.CreateDirectory(s + folder);
                string fileName = Path.GetFileName(url);

                WebClient webClient = new WebClient();
                webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
                webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
                webClient.DownloadFileAsync(new Uri(url), @s + folder + "/" + fileName);
            }
            catch (Exception ex)
            {
                LogService.Service.Error("FAILED TO DOWNLOAD FILES");
                LogService.Service.Error("Folder : " + folder);
                LogService.Service.Error("File : " + url);
                throw;
            }

        }

        private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            Log.WriteCurrent("[DOWNLOADING : " + e.ProgressPercentage);
        }

        private void Completed(object sender, AsyncCompletedEventArgs e)
        {
            Log.WriteLog("[DOWNLOAD COMPLETE]");
        }
    }
}
